using System; 
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Xml;
using System.Xml.Serialization;

namespace ZhiHeng.OneCard.CommUtility
{
    /// <summary>
    /// This class implements helper methods for serialization/deserialization
    /// </summary>
    public static class SerializationHelper
    {
        public static T DeepClone<T>(this T a)
        {
            using (MemoryStream stream = new MemoryStream())
            {
                BinaryFormatter formatter = new BinaryFormatter();
                formatter.Serialize(stream, a);
                stream.Position = 0;
                return (T)formatter.Deserialize(stream);
            }
        }
         

        /// <summary>
        /// Serialize an object using the BinaryFormatter.
        /// </summary>
        /// <param name="item">The object that must be serialized</param>
        /// <returns>A Base64 string.</returns>
        public static string BinarySerialize(object item)
        {
            if (item == null)
            {
                return null;
            }

            using (MemoryStream memoryStream = new MemoryStream())
            {
                BinaryFormatter binaryFormatter = new BinaryFormatter();
                binaryFormatter.Serialize(memoryStream, item);
                return Convert.ToBase64String(memoryStream.ToArray());
            }
        }

        /// <summary>
        /// Deserialize an Base64 string into an object using the BinaryFormatter.
        /// </summary>
        /// <param name="item">The string that must be deserialized.</param>
        /// <returns>The object deserialized.</returns>
        public static T BinaryDeserialize<T>(string item)
        {
            if (item == null || item.Length <= 0) return default(T);
            byte[] buffer = Encoding.UTF8.GetBytes(item);
            if (buffer.Length <= 0)
            {
                return default(T);
            }
            using (var memoryStream = new MemoryStream(Convert.FromBase64String(item)))
            {
                var binaryFormatter = new BinaryFormatter();
                return (T)binaryFormatter.Deserialize(memoryStream);
            }
        }

        /// <summary>
        /// Serialize an object using the XmlSerializer.
        /// </summary>
        /// <param name="item">The object that must be serialized</param>
        /// <returns>A XML string.</returns>
        public static string XmlSerialize(object item)
        {
            string serialXML = String.Empty;
            try
            {
                // Serialize the object
                XmlSerializer xmlSerializer = new XmlSerializer(item.GetType());
                using (StringWriter stringWriter = new StringWriter())
                {
                    xmlSerializer.Serialize(stringWriter, item);
                    serialXML = stringWriter.ToString();
                    stringWriter.Flush();
                }
            }
            catch { }
            return serialXML;
        }

        /// <summary>
        /// Deserialize an XML string into an object using the XmlSerializer.
        /// </summary>
        /// <param name="item">The string that must be deserialized.</param>
        /// <returns>The object deserialized.</returns>
        public static T XmlDeserialize<T>(string item)
        {
            using (StringReader stringReader = new StringReader(item))
            {
                XmlSerializer serializer = new XmlSerializer(typeof(T));
                return (T)serializer.Deserialize(stringReader);
            }
            return default(T);
        }


        public static object XmlDeserialize(Type type,string item)
        {
            using (StringReader stringReader = new StringReader(item))
            {
                XmlSerializer serializer = new XmlSerializer(type);
                return serializer.Deserialize(stringReader);
            } 
        }

        /// <summary>
        /// Serializes object with no namespace and no xml declaration tag. Returns pure xml of the object
        /// </summary>
        /// <param name="item">The object that must be serialized</param>
        /// <returns>A pure XML string</returns>
        public static string XmlSerializeToPureXML(Object item)
        {
            string serialXML = String.Empty;
            // set XML writer settings
            XmlWriterSettings xmlWriterSettings = new XmlWriterSettings();
            xmlWriterSettings.OmitXmlDeclaration = true;
            xmlWriterSettings.Indent = true;
            xmlWriterSettings.CloseOutput = true;
            xmlWriterSettings.Encoding = Encoding.UTF8;

            using (StringWriter stringWriter = new StringWriter())
            {
                // create xml using the settings
                using (XmlWriter xmlWriter = XmlWriter.Create(stringWriter, xmlWriterSettings))
                {
                    XmlSerializer xmlSerializer = new XmlSerializer(item.GetType());
                    //Empty namespace
                    XmlSerializerNamespaces xmlSerializerNamespaces = new XmlSerializerNamespaces();
                    xmlSerializerNamespaces.Add(String.Empty,String.Empty);

                    xmlSerializer.Serialize(xmlWriter, item, xmlSerializerNamespaces);
                    // get the xml and clean up
                    serialXML = stringWriter.ToString();
                    xmlWriter.Flush();
                }
                stringWriter.Flush();
            }
            //
            return serialXML;
        }

        /// <summary>
        /// Serialize with no xml declaration
        /// </summary>
        /// <param name="item">The type of the serialized object.</param>
        /// <returns>A XML with string with no xml declaration</returns>
        public static string XmlSerializeWithNoXmlDeclaration(Object item)
        {
            string serialXML = String.Empty;
            // set XML writer settings
            XmlWriterSettings xmlWriterSettings = new XmlWriterSettings();
            xmlWriterSettings.OmitXmlDeclaration = true;
            xmlWriterSettings.Indent = true;
            xmlWriterSettings.CloseOutput = true;
            xmlWriterSettings.Encoding = Encoding.UTF8;

            using (StringWriter stringWriter = new StringWriter())
            {
                // create xml using the settings
                using (XmlWriter xmlWriter = XmlWriter.Create(stringWriter, xmlWriterSettings))
                {
                    XmlSerializer xmlSerializer = new XmlSerializer(item.GetType());
                    xmlSerializer.Serialize(xmlWriter, item);
                    // get the xml and clean up
                    serialXML = stringWriter.ToString();
                    xmlWriter.Flush();
                }
                stringWriter.Flush();
            }
            //
            return serialXML;
        }

        /// <summary>
        /// Serialize an object using the DataContractSerializer.
        /// </summary>
        /// <param name="item">The object that must be serialized</param>
        /// <returns>A XML string.</returns>
        public static string DataContractSerialize(object item)
        {
            if (item == null)
            {
                return null;
            }
            using (MemoryStream memoryStream = new MemoryStream())
            {
                //DataContractSerializer serializer = new DataContractSerializer(item.GetType(), item.GetType().Name, string.Empty);
                DataContractSerializer serializer = new DataContractSerializer(item.GetType());
                serializer.WriteObject(memoryStream, item);
                return Encoding.UTF8.GetString(memoryStream.ToArray());
            }
        }

        /// <summary>
        /// Deserialize an XML string into an object using the DataContractSerializer.
        /// </summary>
        /// <param name="item">The string that must be deserialized.</param>
        /// <returns>The object deserialized.</returns>
        public static T DataContractDeserialize<T>(string item)
        {
            XmlDictionaryReader xmlDictionaryReader = null;
            try
            {
                xmlDictionaryReader = XmlDictionaryReader.CreateTextReader(Encoding.UTF8.GetBytes(item), XmlDictionaryReaderQuotas.Max);
                DataContractSerializer serializer = new DataContractSerializer(typeof(T));
                return (T)serializer.ReadObject(xmlDictionaryReader, false);
            }
            finally
            {
                if (xmlDictionaryReader != null)
                {
                    xmlDictionaryReader.Close();
                }
            }
            return default(T);
        }


        public static object DataContractDeserialize(Type t,string item)
        {
            XmlDictionaryReader xmlDictionaryReader = null;
            try
            {
                xmlDictionaryReader = XmlDictionaryReader.CreateTextReader(Encoding.UTF8.GetBytes(item), XmlDictionaryReaderQuotas.Max);
                DataContractSerializer serializer = new DataContractSerializer(t);
                return serializer.ReadObject(xmlDictionaryReader, false);
            }
            finally
            {
                if (xmlDictionaryReader != null)
                {
                    xmlDictionaryReader.Close();
                }
            }
            return null;
        }
        
    }

}